/*
 *  Copyright © 2018 - 2021 xulianqiang90@163.com. All Rights Reserved.
 */

package io.light.frame.dal.mybatis.generator.core.domain.mapper;

import com.google.common.base.CaseFormat;
import com.google.common.base.Converter;
import io.light.frame.dal.mybatis.generator.core.domain.clazz.Clazz;
import io.light.frame.dal.mybatis.generator.core.meta.entity.Table;
import io.light.frame.dal.mybatis.generator.core.meta.entity.TableColumn;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.apache.ibatis.type.JdbcType;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Mapper
 *
 * @author Ivan
 * @version 1.0.0
 * @date 2021-05-17 09:26
 */
@Getter
@Setter
@ToString
public class Mapper {
    public static final Converter<String, String> FIELD_NAME_CAMEL_CONVERTER = CaseFormat.LOWER_UNDERSCORE.converterTo(
            CaseFormat.LOWER_CAMEL);
    private final Table table;
    private final List<Property> properties = new ArrayList<>();
    private final List<Property> primaryKeys = new ArrayList<>();
    private final List<Property> hasDefaultProperties = new ArrayList<>();
    private final List<Property> insertProperties = new ArrayList<>();
    private final List<Property> updateProperties = new ArrayList<>();
    private final List<MapperFunc> funcList = new ArrayList<>();
    private final List<String> sqlList = new ArrayList<>();
    private Clazz entityClazz;
    private Clazz daoClazz;

    public Mapper(Table table) {
        table.setName(table.getName().toLowerCase());
        this.table = table;
        List<TableColumn> columns = table.getColumns();
        if (!CollectionUtils.isEmpty(columns)) {
            columns.stream().map(c -> new Property(table, c)).forEach(property -> {
                properties.add(property);
                if (property.isPrimaryKey()) {
                    primaryKeys.add(property);
                }
                if (property.hasDefaultValue()) {
                    hasDefaultProperties.add(property);
                }
                if (!property.isInsertIgnore()) {
                    insertProperties.add(property);
                }
                if (!property.isUpdateIgnore()) {
                    updateProperties.add(property);
                }
            });
            Collections.sort(properties);
            Collections.sort(primaryKeys);
            Collections.sort(hasDefaultProperties);
            insertProperties.sort((o1, o2) -> {
                if (o1.hasDefaultValue() && !o2.hasDefaultValue()) {
                    return 1;
                } else if (!o1.hasDefaultValue() && o2.hasDefaultValue()) {
                    return -1;
                } else {
                    return o1.compareTo(o2);
                }
            });
            Collections.sort(updateProperties);
        }
    }

    @Getter
    @Setter
    @ToString
    public static class Property implements Comparable<Property> {
        private final Table table;
        private final TableColumn column;
        private final String columnName;
        private final String propertyName;
        private final String comment;
        private final boolean primaryKey;
        private boolean insertIgnore;
        private boolean updateIgnore;
        private JdbcType jdbcType;
        private Clazz javaType;
        private String tableAlias;
        private String columnAlias;

        public Property(Table table, TableColumn column) {
            this.table = table;
            this.column = column;
            this.columnName = column.getName();
            this.comment = column.getComment();
            this.propertyName = FIELD_NAME_CAMEL_CONVERTER.convert(column.getName());
            this.primaryKey = column.isPrimaryKey();
            this.insertIgnore = column.isCanIgnoreOnInsert();
            this.updateIgnore = column.isCanIgnoreOnUpdate();
        }

        public boolean hasDefaultValue() {
            return column.getDefaultValue() != null;
        }

        @Override
        public int compareTo(Property o) {
            if (o == this) {
                return 0;
            }
            if (o == null) {
                return -1;
            }
            if (column.isPrimaryKey() && !o.isPrimaryKey()) {
                return -1;
            } else if (!column.isPrimaryKey() && o.isPrimaryKey()) {
                return 1;
            } else {
                Integer thisSort = column.getPosition();
                thisSort = thisSort == null ? 0 : thisSort;
                Integer otherSort = o.getColumn().getPosition();
                otherSort = otherSort == null ? 0 : otherSort;
                return thisSort - otherSort;
            }
        }
    }
}
